/*
 * SuperBlock.cpp
 *
 *  Created on: 28 Apr 2011
 *      Author: Marc Kampherbeek
 */

#include "SuperBlock.h"
#include "FreeBlock.h"
#include "FS.h"

SuperBlock::~SuperBlock() {
	isize = 0;
	fsize = 0;
	ninode = 0;
	flock = 0;
	ilock = 0;
	fmod = 0;
	ronly = 0;
	time = 0;
	tfree = 0;
	tinode = 0;
	m = 0;
	n = 0;
	for (int i = 0; i < 100; i++) {
		inodes[i] = 0;
	}
	delete inodes;
	delete fname;
	delete fpack;
}

void SuperBlock::parseSuperBlock() {
	int offset = 0;
	isize = readUShort(offset); //unsigned short
	offset += 2;
	fsize = readLong(offset);
	offset += 4;
	byte freeb[204];
	freeb[0] = 0;
	freeb[1] = 0;
	for(int i = 2; i < 204; i++){
		freeb[i] = readByte(offset);
		offset++;
	}
	freeblock = new FreeBlock(0, freeb);
	ninode = readShort(offset); //normal short
	offset += 2;
	for (int i = 0; i < 100; i++) {
		inodes[i] = readUShort(offset); //unsigned short
		offset += 2;
	}
	flock = readByte(offset);
	offset++;
	ilock = readByte(offset);
	offset++;
	fmod = readByte(offset);
	offset++;
	ronly = readByte(offset);
	offset++;
	time = readLong(offset);
	offset += 4;
	tfree = readLong(offset);
	offset += 4;
	tinode = readUShort(offset); //unsigned short
	offset += 2;
	m = readShort(offset); //normal short
	offset += 2;
	n = readShort(offset); //normal short
	offset += 2;
	for (int i = 0; i < 6; i++) {
		fname[i] = readByte(offset);
		offset++;
	}
	for (int i = 0; i < 6; i++) {
		fpack[i] = readByte(offset);
		offset++;
	}
}

Inode* SuperBlock::getFreeInode(){
	if(ninode > 0){
		cout << "punt s1" << endl;
		int inum = inodes[ninode-1];
		cout << inum << endl;
		cout << "punt s2" << endl;
		inodes[ninode] = 0;
		cout << "punt s3" << endl;
		ninode--;
		Inode* i = new Inode(new InodeBlock((inum-1)/8+2, FS::getInstance()->readBlock((inum-1)/8)), inum);
		cout << "punt s4" << endl;
		i->reset();
		cout << "punt s5" << endl;
		byte newnino[2];
		byte* ib = (byte*) &ninode;
		if (isBigEndian()) {
			newnino[0] = ib[2];
			newnino[1] = ib[3];
		} else {
			newnino[0] = ib[1];
			newnino[1] = ib[0];
		}
		FS::getInstance()->writeInBlock(1, 208, newnino, 2);
		return i;
	}else{
		scanForFreeInodes();
		if(ninode > 0){
			return getFreeInode();
		}else{
			return 0;
		}
	}
}

void SuperBlock::scanForFreeInodes(){
	FS* fs = FS::getInstance();
	for(int i = 2; i < isize+2; i++){ //current inode block
		for(int x = 1; x < 9; x++){	  //inode within current block
			int inum = (i-2)*8+x;
			Inode* inod = new Inode(new InodeBlock(i, fs->readBlock(i)), inum);
			if(inod->modeString().substr(0,1).compare("0") == 0){
				inodes[ninode] = inod->getInodeNr();
				ninode++;
				if(ninode == 100){
					return;
				}
			}
		}
	}
	writeFreeInodeList();
}

void SuperBlock::writeFreeInodeList(){
	byte newilist[(ninode*2)+2];
	byte* ib = (byte*) &ninode;
	if(isBigEndian()){
		newilist[0] = ib[2];
		newilist[1] = ib[3];
	}else{
		newilist[0] = ib[1];
		newilist[1] = ib[0];
	}
	for(int i = 0; i < ninode; i++){
		ib = (byte*) &inodes[i];
		if(isBigEndian()){
			newilist[(i*2)+2] = ib[2];
			newilist[(i*2)+3] = ib[3];
		}else{
			newilist[(i*2)+2] = ib[1];
			newilist[(i*2)+3] = ib[0];
		}
	}
	FS::getInstance()->writeInBlock(1, 208, newilist, (ninode*2)+2);
}

void SuperBlock::print() {
	cout << "...SUPERBLOCK..." << endl;
	cout << "size in blocks in i-list: " << isize << endl;
	cout << "size in blocks on volume: " << fsize << endl;
	/*
	//testing purpose
	cout << "number of free blocks in free[]: " << nfree << endl;
	cout << "adresses of free blocks:" << endl;
	for (int i = 0; i < nfree; i++) {
		cout << free[i] << " ";
	}
	*/
	freeblock->print();
	cout << endl << "number of inodes in inode list: " << ninode << endl;
	for (int i = 0; i < ninode; i++) {
		cout << inodes[i] << " ";
	}
	cout << endl;
	cout << "free list lock: " << flock << endl;
	cout << "inode list lock: " << ilock << endl;
	cout << "superblock modified: " << fmod << endl;
	cout << "filesystem read-only:  " << ronly << endl;
	cout << "last modification: " << ctime(&time) << endl;
	cout << "number of free blocks: " << tfree << endl;
	cout << "number of free inodes: " << tinode << endl;
	cout << "interleave factor: " << m << endl;
	cout << "cylinder size: " << n << endl;
	cout << "file system name: " << fname << endl;
	cout << "file system pack: " << fpack << endl << endl;
}
